﻿using System;
using System.Text;

namespace NamedBinaryTag
{
	/// <summary>
	/// Represents a <see cref="System.IO.Stream"/> that dumps the read requests to Console if the DebugFlag 1 is set and in Debug mode.
	/// </summary>
	public class DumpStream : System.IO.Stream, IDisposable
	{
		private static int nextValue = 1;
		private int value;
		private System.IO.FileStream outputCopy;

		public static string DumpData { get; set; }

		static DumpStream()
		{
			DumpData = null;
		}

		internal System.IO.Stream BaseStream { get; private set; }

		public DumpStream(System.IO.Stream baseStream)
		{
			value = nextValue++;
			BaseStream = baseStream;
			if (DebugFlags.GetDebug(1))
				Console.WriteLine("Open DumpStream ({0})", value);
			if (!string.IsNullOrEmpty(DumpData))
				outputCopy = new System.IO.FileStream(System.IO.Path.Combine(DumpData, string.Format("Dump{0}.bin", value)), System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
		}

		protected override void Dispose(bool disposing)
		{
			base.Dispose(disposing);
			if (disposing)
			{
				if (DebugFlags.GetDebug(1) && (value > 0))
				{
					Console.WriteLine("Close DumpStream ({0})", value);
					value = 0;
				}
				if (outputCopy != null)
				{
					outputCopy.Flush();
					outputCopy.Close();
					outputCopy = null;
				}
			}
		}

		public override bool CanRead
		{
			get { return BaseStream.CanRead; }
		}

		public override bool CanSeek
		{
			get { return BaseStream.CanSeek; }
		}

		public override bool CanWrite
		{
			get { return BaseStream.CanWrite; }
		}

		public override void Flush()
		{
			BaseStream.Flush();
		}

		public override long Length
		{
			get { return BaseStream.Length; }
		}

		public override long Position
		{
			get
			{
				return BaseStream.Position;
			}
			set
			{
				BaseStream.Position = value;
			}
		}

		public override int Read(byte[] buffer, int offset, int count)
		{
#if DEBUG
			if (!DebugFlags.GetDebug(1))
			{
				return BaseStream.Read(buffer, offset, count);
			}
			Console.WriteLine("({1}) Action: Read {0} bytes.", count, value);
			int read = 0;
			try
			{
				read = BaseStream.Read(buffer, offset, count);
				if (outputCopy != null)
					outputCopy.Write(buffer, offset, read);
				StringBuilder output = new StringBuilder();
				for (int i = 0; i < read; i++)
				{
					output.Append(buffer[offset + i].ToString("X2"));
				}
				Console.WriteLine("({2}) Result: Read {0} bytes. {1}", read, output.ToString(), value);
			}
			catch (Exception e)
			{
				Console.WriteLine("({1}) Result: Read error. {0}", e, value);
				throw;
			}
			return read;
#else
			return BaseStream.Read(buffer, offset, count);
#endif
		}

		public override long Seek(long offset, System.IO.SeekOrigin origin)
		{
			return BaseStream.Seek(offset, origin);
		}

		public override void SetLength(long value)
		{
			BaseStream.SetLength(value);
		}

		public override void Write(byte[] buffer, int offset, int count)
		{
			BaseStream.Write(buffer, offset, count);
		}
	}
}
